/**
 * 
 */
package com.dalonedrow.engine.sprite.base;

/**
 * @author DaLoneDrow
 */
public final class SimpleRectangle {
	/**
	 * The height of the <code>SimpleRectangle</code>.
	 */
	private int	height;
	/**
	 * The width of the <code>SimpleRectangle</code>.
	 */
	private int	width;
	/**
	 * The X coordinate of the upper-left corner of the
	 * <code>SimpleRectangle</code>.
	 */
	private int	x;
	/**
	 * The Y coordinate of the upper-left corner of the
	 * <code>SimpleRectangle</code>.
	 */
	private int	y;
	/**
	 * Constructs a new <code>SimpleRectangle</code> whose upper-left corner is
	 * at (0,&nbsp;0) in the coordinate space, and whose width and height are
	 * both zero.
	 */
	public SimpleRectangle() {
		this(0, 0, 0, 0);
	}
	/**
	 * Constructs a new <code>SimpleRectangle</code> whose upper-left corner is
	 * at (0,&nbsp;0) in the coordinate space, and whose width and height are
	 * specified by the arguments of the same name.
	 * @param newWidth the width of the <code>SimpleRectangle</code>
	 * @param newHeight the height of the <code>SimpleRectangle</code>
	 */
	public SimpleRectangle(final int newWidth, final int newHeight) {
		this(0, 0, newWidth, newHeight);
	}
	/**
	 * Constructs a new <code>SimpleRectangle</code> whose upper-left corner is
	 * specified as {@code (x,y)} and whose width and height are specified by
	 * the arguments of the same name.
	 * @param newX the specified X coordinate
	 * @param newY the specified Y coordinate
	 * @param newWidth the width of the <code>SimpleRectangle</code>
	 * @param newHeight the height of the <code>SimpleRectangle</code>
	 * @since 1.0
	 */
	public SimpleRectangle(final int newX, final int newY, final int newWidth,
			final int newHeight) {
		x = newX;
		y = newY;
		width = newWidth;
		height = newHeight;
	}
	/**
	 * Constructs a new <code>SimpleRectangle</code> whose top left corner is
	 * (0,&nbsp;0) and whose width and height are specified by the
	 * <code>SimpleDimension</code> argument.
	 * @param d a <code>SimpleDimension</code>, specifying width and height
	 */
	public SimpleRectangle(final SimpleDimension d) {
		this(0, 0, d.width, d.height);
	}
	/**
	 * Constructs a new <code>SimpleRectangle</code>, initialized to match the
	 * values of the specified <code>SimpleRectangle</code>.
	 * @param r the <code>SimpleRectangle</code> from which to copy initial
	 *        values to a newly constructed <code>SimpleRectangle</code>
	 * @since 1.1
	 */
	public SimpleRectangle(final SimpleRectangle r) {
		this(r.x, r.y, r.width, r.height);
	}
	/**
	 * Constructs a new <code>SimpleRectangle</code> whose upper-left corner is
	 * the specified <code>SimpleVector2</code>, and whose width and height are
	 * both zero.
	 * @param p a <code>SimpleVector2</code> that is the top left corner of the
	 *        <code>SimpleRectangle</code>
	 */
	public SimpleRectangle(final SimpleVector2 p) {
		this((int) p.getX(), (int) p.getY(), 0, 0);
	}

	/**
	 * Constructs a new <code>SimpleRectangle</code> whose upper-left corner is
	 * specified by the {@link SimpleVector2} argument, and whose width and
	 * height are specified by the {@link SimpleDimension} argument.
	 * @param p a <code>SimpleVector2</code> that is the upper-left corner of
	 *        the <code>SimpleRectangle</code>
	 * @param d a <code>SimpleDimension</code>, representing the width and
	 *        height of the <code>SimpleRectangle</code>
	 */
	public SimpleRectangle(final SimpleVector2 p, final SimpleDimension d) {
		this((int) p.getX(), (int) p.getY(), d.width, d.height);
	}
	/**
     * Checks whether or not this <code>Rectangle</code> contains the 
     * point at the specified location {@code (x,y)}.
     *
     * @param  x the specified X coordinate
     * @param  y the specified Y coordinate
     * @return    <code>true</code> if the point 
     *            {@code (x,y)} is inside this 
     *		  <code>Rectangle</code>; 
     *            <code>false</code> otherwise.
     * @since     1.1
     */
    public boolean contains(int X, int Y) {
    	int w = this.width;
    	int h = this.height;
    	if ((w | h) < 0) {
    	    // At least one of the dimensions is negative...
    	    return false;
    	}
    	// Note: if either dimension is zero, tests below must return false...
    	int x = this.x;
    	int y = this.y;
    	if (X < x || Y < y) {
    	    return false;
    	}
    	w += x;
    	h += y;
    	//    overflow || intersect
    	return ((w < x || w > X) &&
    		(h < y || h > Y));
    }
	/**
	 * Checks whether this <code>SimpleRectangle</code> entirely contains the
	 * <code>SimpleRectangle</code> at the specified location {@code (X,Y)} with
	 * the specified dimensions {@code (W,H)}.
	 * @param X the specified X coordinate
	 * @param Y the specified Y coordinate
	 * @param W the width of the <code>SimpleRectangle</code>
	 * @param H the height of the <code>SimpleRectangle</code>
	 * @return <code>true</code> if the <code>SimpleRectangle</code> specified
	 *         by {@code (X, Y, W, H)} is entirely enclosed inside this
	 *         <code>SimpleRectangle</code>; <code>false</code> otherwise.
	 */
	public boolean contains(final int X, final int Y, int W, int H) {
		int w = width;
		int h = height;
		if ((w | h | W | H) < 0) {
			// At least one of the dimensions is negative...
			return false;
		}
		// Note: if any dimension is zero, tests below must return false...
		int x = this.x;
		int y = this.y;
		if (X < x || Y < y) {
			return false;
		}
		w += x;
		W += X;
		if (W <= X) {
			// X+W overflowed or W was zero, return false if...
			// either original w or W was zero or
			// x+w did not overflow or
			// the overflowed x+w is smaller than the overflowed X+W
			if (w >= x || W > w) {
				return false;
			}
		} else {
			// X+W did not overflow and W was not zero, return false if...
			// original w was zero or
			// x+w did not overflow and x+w is smaller than X+W
			if (w >= x && W > w) {
				return false;
			}
		}
		h += y;
		H += Y;
		if (H <= Y) {
			if (h >= y || H > h) {
				return false;
			}
		} else {
			if (h >= y && H > h) {
				return false;
			}
		}
		return true;
	}
	/**
	 * Checks whether or not this <code>SimpleRectangle</code> entirely contains
	 * the specified <code>SimpleRectangle</code>.
	 * @param r the specified <code>SimpleRectangle</code>
	 * @return <code>true</code> if the <code>SimpleRectangle</code> is
	 *         contained entirely inside this <code>SimpleRectangle</code>;
	 *         <code>false</code> otherwise
	 * @since 1.2
	 */
	public boolean contains(SimpleRectangle r) {
		return contains(r.x, r.y, r.width, r.height);
	}
	/**
	 * Returns the height of the bounding <code>SimpleRectangle</code> in
	 * <code>double</code> precision.
	 * @return the height of the bounding <code>SimpleRectangle</code>.
	 */
	public double getHeight() {
		return height;
	}
	/**
	 * Returns the largest X coordinate of the framing rectangle of the
	 * <code>SimpleRectangle</code> in <code>double</code> precision.
	 * @return the largest X coordinate of the framing rectangle of the
	 *         <code>SimpleRectangle</code>.
	 */
	public double getMaxX() {
		return x + getWidth();
	}
	/**
	 * Returns the largest Y coordinate of the framing rectangle of the
	 * <code>SimpleRectangle</code> in <code>double</code> precision.
	 * @return the largest Y coordinate of the framing rectangle of the
	 *         <code>SimpleRectangle</code>.
	 * @since 1.2
	 */
	public double getMaxY() {
		return y + getHeight();
	}
	/**
	 * Returns the smallest X coordinate of the framing rectangle of the
	 * <code>SimpleRectangle</code> in <code>double</code> precision.
	 * @return the smallest X coordinate of the framing rectangle of the
	 *         <code>SimpleRectangle</code>.
	 */
	public double getMinX() {
		return x;
	}
	/**
	 * Returns the smallest Y coordinate of the framing rectangle of the
	 * <code>SimpleRectangle</code> in <code>double</code> precision.
	 * @return the smallest Y coordinate of the framing rectangle of the
	 *         <code>SimpleRectangle</code>.
	 */
	public double getMinY() {
		return y;
	}
	/**
	 * Returns the width of the bounding <code>SimpleRectangle</code> in
	 * <code>double</code> precision.
	 * @return the width of the bounding <code>SimpleRectangle</code>.
	 */
	public double getWidth() {
		return width;
	}
	/**
	 * Returns the X coordinate of the bounding <code>SimpleRectangle</code> in
	 * <code>double</code> precision.
	 * @return the X coordinate of the bounding <code>SimpleRectangle</code>.
	 */
	public double getX() {
		return x;
	}
	/**
	 * Returns the Y coordinate of the bounding <code>SimpleRectangle</code> in
	 * <code>double</code> precision.
	 * @return the Y coordinate of the bounding <code>SimpleRectangle</code>.
	 */
	public double getY() {
		return y;
	}
	/**
	 * Determines whether or not this <code>SimpleRectangle</code> and the
	 * specified <code>SimpleRectangle</code> intersect. Two rectangles
	 * intersect if their intersection is nonempty.
	 * @param r the specified <code>SimpleRectangle</code>
	 * @return <code>true</code> if the specified <code>SimpleRectangle</code>
	 *         and this <code>SimpleRectangle</code> intersect;
	 *         <code>false</code> otherwise.
	 */
	public boolean intersects(final SimpleRectangle r) {
		int tw = width;
		int th = height;
		int rw = r.width;
		int rh = r.height;
		if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
			return false;
		}
		int tx = x;
		int ty = y;
		int rx = r.x;
		int ry = r.y;
		rw += rx;
		rh += ry;
		tw += tx;
		th += ty;
		// overflow || intersect
		return (rw < rx || rw > tx) &&
				(rh < ry || rh > ty) &&
				(tw < tx || tw > rx) &&
				(th < ty || th > ry);
	}
}
